home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 19 / CU Amiga Magazine's Super CD-ROM 19 (1998)(EMAP Images)(GB)[!][issue 1998-02].iso / CUCD / Programming / LEDA / source / src / plane / _sweep_segments.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-16  |  13.4 KB  |  587 lines

  1. /*******************************************************************************
  2. +
  3. +  LEDA  3.1c
  4. +
  5. +
  6. +  _sweep_segments.c
  7. +
  8. +
  9. +  Copyright (c) 1994  by  Max-Planck-Institut fuer Informatik
  10. +  Im Stadtwald, 6600 Saarbruecken, FRG     
  11. +  All rights reserved.
  12. *******************************************************************************/
  13.  
  14.  
  15. //------------------------------------------------------------------------------
  16. //
  17. // SWEEP_SEGMENTS
  18. //
  19. // a plane sweep algorithm for computing line segment intersections
  20. //
  21. // SWEEP_SEGMENTS(list<segment>& L1, list<segment>& L2, GRAPH<point,int> G);
  22. //
  23. // computes the planar subdivision created by the (directed) straight
  24. // line segments of L1 and L2
  25. // 
  26. // G = (V,E) with
  27. //
  28. // 1. each node v in V contains a point of intersectoin between two segments
  29. //    (from L1 or L2)
  30. //
  31. // 2. each edge e = (v,w) corresponds to a
  32. //
  33. //
  34. //------------------------------------------------------------------------------
  35.  
  36.  
  37. #include <LEDA/sweep_segments.h>
  38. #include <LEDA/sortseq.h>
  39. #include <LEDA/prio.h>
  40. #include <math.h>
  41.  
  42.  
  43. #define EPS  0.00001
  44. #define EPS2 0.0000000001
  45.  
  46. class S_POINT;
  47. class S_SEGMENT;
  48. typedef S_POINT* S_point;
  49. typedef S_SEGMENT* S_segment;
  50.  
  51. enum S_point_type {Cross=0,Rightend=1,Leftend=2}; 
  52.  
  53. class S_POINT
  54. {
  55.   friend class S_SEGMENT;
  56.  
  57.   S_segment seg;
  58.   int     kind;
  59.   double  x;
  60.   double  y;
  61.  
  62.   public:
  63.  
  64.   S_POINT(double a,double b)  
  65.   { 
  66.     x=a; y=b; seg=0; kind=Cross;
  67.    }
  68.  
  69.  
  70.  
  71.   S_POINT(point p)         
  72.   { 
  73.     x=p.xcoord();y=p.ycoord();seg=0;kind=Cross;
  74.    }
  75.  
  76.  
  77.   LEDA_MEMORY(S_POINT);
  78.  
  79.   friend double    get_x(S_point);
  80.   friend double    get_y(S_point);
  81.   friend int       get_kind(S_point);
  82.   friend S_segment get_seg(S_point);
  83.  
  84.   friend bool intersection(S_segment, S_segment, S_point&);
  85. };
  86.  
  87. inline double    get_x(S_point p)    { return p->x; }
  88. inline double    get_y(S_point p)    { return p->y; }
  89. inline int       get_kind(S_point p) { return p->kind; }
  90. inline S_segment get_seg(S_point p)  { return p->seg; }   
  91.  
  92.  
  93.  
  94. static int compare(const S_point& p1, const S_point& p2)
  95. { if (p1==p2) return 0;
  96.  
  97.   double diffx = get_x(p1) - get_x(p2);
  98.   if (diffx >  EPS2 ) return  1;
  99.   if (diffx < -EPS2 ) return -1;
  100.  
  101.   int    diffk = get_kind(p1)-get_kind(p2);
  102.   if (diffk != 0) return diffk;
  103.  
  104.   double diffy = get_y(p1) - get_y(p2);
  105.   if (diffy >  EPS2 ) return  1;
  106.   if (diffy < -EPS2 ) return -1;
  107.  
  108.   return 0;
  109.  
  110. }
  111.  
  112.  
  113. class S_SEGMENT
  114. {
  115.   S_point startpoint;
  116.   S_point endpoint;
  117.   double  slope;
  118.   double  yshift;
  119.   node  left_node;
  120.   int   orient;
  121.   int   color;
  122.   int   name;
  123.  
  124.  
  125.   public:
  126.  
  127.   S_SEGMENT(S_point, S_point,int,int);     
  128.  
  129.  ~S_SEGMENT() { delete startpoint; delete endpoint; }     
  130.  
  131.   LEDA_MEMORY(S_SEGMENT);
  132.  
  133.   friend S_point get_startpoint(S_segment);
  134.   friend S_point get_endpoint(S_segment);
  135.   friend double get_slope(S_segment);
  136.   friend double get_yshift(S_segment);
  137.   friend int  get_orient(S_segment);
  138.   friend int  get_color(S_segment);
  139.   friend int  get_name(S_segment);
  140.   friend node get_left_node(S_segment);
  141.   friend void set_left_node(S_segment, node);
  142.  
  143.   friend bool intersection(S_segment, S_segment, S_point&);
  144. };
  145.  
  146.  
  147. inline S_point get_startpoint(S_segment seg)     { return seg->startpoint; }
  148. inline S_point get_endpoint(S_segment seg)       { return seg->endpoint; }
  149. inline double get_slope(S_segment seg)           { return seg->slope; }
  150. inline double get_yshift(S_segment seg)          { return seg->yshift; }
  151. inline int  get_orient(S_segment seg)            { return seg->orient; }
  152. inline int  get_color(S_segment seg)             { return seg->color; }
  153. inline int  get_name(S_segment seg)              { return seg->name; }
  154. inline node get_left_node(S_segment seg)         { return seg->left_node; }
  155. inline void set_left_node(S_segment seg, node v) { seg->left_node = v; }
  156.  
  157.  
  158.  
  159. S_SEGMENT::S_SEGMENT(S_point p1,S_point p2,int c, int n)    
  160.   {
  161.     left_node  = nil;
  162.     color      = c;
  163.     name       = n;
  164.  
  165.     if (compare(p1,p2) < 0)
  166.      { startpoint = p1; 
  167.        endpoint = p2; 
  168.        orient = 0;
  169.       }
  170.     else
  171.      { startpoint = p2; 
  172.        endpoint = p1; 
  173.        orient = 1;
  174.       }
  175.  
  176.     startpoint->kind = Leftend; 
  177.     endpoint->kind = Rightend; 
  178.     startpoint->seg = this; 
  179.     endpoint->seg = this;
  180.  
  181.     if (endpoint->x != startpoint->x)
  182.     {
  183.       slope = (endpoint->y - startpoint->y)/(endpoint->x - startpoint->x);
  184.       yshift = startpoint->y - slope * startpoint->x;
  185.  
  186.       startpoint->x -= EPS;
  187.       startpoint->y -= EPS * slope;
  188.       endpoint->x += EPS;
  189.       endpoint->y += EPS * slope;
  190.     }
  191.     else //vertical segment
  192.     { startpoint->y -= EPS;
  193.       endpoint->y   += EPS;
  194.      }
  195.   }
  196.  
  197.  
  198. static double x_sweep;
  199. static double y_sweep;
  200.  
  201.  
  202. static int compare(const S_segment& s1, const S_segment& s2)
  203. {
  204.   double y1 = get_slope(s1)*x_sweep+get_yshift(s1);
  205.   double y2 = get_slope(s2)*x_sweep+get_yshift(s2);
  206.  
  207.   double diff = y1-y2;
  208.   if (diff >  EPS2 ) return  1;
  209.   if (diff < -EPS2 ) return -1;
  210.  
  211.   if (get_slope(s1) == get_slope(s2)) 
  212.         return compare(get_x(get_startpoint(s1)), get_x(get_startpoint(s2)));
  213.  
  214.   if (y1 <= y_sweep+EPS2)
  215.         return compare(get_slope(s1),get_slope(s2));
  216.   else
  217.         return compare(get_slope(s2),get_slope(s1));
  218.  
  219. }
  220.  
  221.  
  222. void Print(S_segment& x) 
  223. { S_point s = get_startpoint(x);
  224.   S_point e = get_endpoint(x);
  225.   cout << 
  226.     string("[(%f,%f)----(%f,%f)]",get_x(s),get_y(s), get_x(e),get_y(e));
  227. }
  228.  
  229.  
  230. static priority_queue<seq_item,S_point> X_structure;
  231.  
  232. static sortseq<S_segment,pq_item> Y_structure;
  233.  
  234.  
  235. bool intersection(S_segment seg1,S_segment seg2, S_point& inter)
  236. {
  237.   if (seg1->slope == seg2->slope)
  238.     return false;
  239.   else
  240.   { 
  241.     double cx = (seg2->yshift - seg1->yshift) / (seg1->slope - seg2->slope);
  242.  
  243.     if (cx <= x_sweep) return false;
  244.  
  245.     if (seg1->startpoint->x > cx || seg2->startpoint->x > cx ||
  246.         seg1->endpoint->x < cx || seg2->endpoint->x < cx ) return false;
  247.  
  248.     inter = new S_POINT(cx,seg1->slope * cx + seg1->yshift);
  249.  
  250.     return true;
  251.   }
  252. }
  253.  
  254.  
  255. static pq_item Xinsert(seq_item i, S_point p) 
  256.   return X_structure.insert(i,p);
  257. }
  258.  
  259. static S_point Xdelete(pq_item i) 
  260. {
  261.   S_point p = X_structure.inf(i);
  262.   X_structure.del_item(i);
  263.   return p;
  264. }
  265.  
  266.  
  267. static node New_Node(GRAPH<point,int>& G,double x, double y )
  268. { return G.new_node(point(x,y)); }
  269.  
  270. static void New_Edge(GRAPH<point,int>& G,node v, node w, S_segment l )
  271. { if (get_orient(l)==0)
  272.        G.new_edge(v,w,get_color(l));
  273.   else G.new_edge(w,v,get_color(l));
  274. }
  275.  
  276.  
  277. void handle_vertical_segment(GRAPH<point,int>& SUB, S_segment l)
  278.   S_point p = new S_POINT(get_x(get_startpoint(l)),get_y(get_startpoint(l)));
  279.   S_point q = new S_POINT(get_x(get_endpoint(l)),get_y(get_endpoint(l)));
  280.  
  281.   S_point r = new S_POINT(get_x(p)+1,get_y(p));
  282.   S_point s = new S_POINT(get_x(q)+1,get_y(q));
  283.  
  284.   S_segment bot = new S_SEGMENT(p,r,0,0);
  285.   S_segment top = new S_SEGMENT(q,s,0,0);
  286.  
  287.   seq_item bot_it = Y_structure.insert(bot,nil);
  288.   seq_item top_it = Y_structure.insert(top,nil);
  289.   seq_item sit;
  290.  
  291.   node u,v,w;
  292.   S_segment seg;
  293.   
  294.  
  295.   for(sit=Y_structure.succ(bot_it); sit != top_it; sit=Y_structure.succ(sit))
  296.   { seg = Y_structure.key(sit);
  297.  
  298.     double cross_y = (get_slope(seg) * get_x(p) + get_yshift(seg));
  299.  
  300.     v = get_left_node(seg);
  301.     if (v==nil)
  302.     { w = New_Node(SUB,get_x(p),cross_y);
  303.       set_left_node(seg,w);
  304.      }
  305.     else
  306.     { double vx = SUB[v].xcoord();
  307.       if ( vx < get_x(p)-EPS2) 
  308.       { w = New_Node(SUB,get_x(p),cross_y);
  309.         New_Edge(SUB,v,w,seg);
  310.         set_left_node(seg,w);
  311.        }
  312.       else w = v;
  313.      }
  314.  
  315.     u = get_left_node(l);
  316.     if (u!=nil && u!=w) New_Edge(SUB,u,w,l);
  317.     set_left_node(l,w);
  318.  
  319.    }
  320.   
  321.   delete l;
  322.   delete top;
  323.   delete bot;
  324.     
  325.   Y_structure.del_item(bot_it);
  326.   Y_structure.del_item(top_it);
  327.  
  328.  }
  329.  
  330.  
  331. void SWEEP_SEGMENTS(const list<segment>& S, list<point>& P)
  332. { GRAPH<point,int> G;
  333.   list<segment> S0;
  334.  
  335.   SWEEP_SEGMENTS(S,S0,G);
  336.  
  337.   node v;
  338.   forall_nodes(v,G) P.append(G[v]);
  339.  
  340. }
  341.  
  342. void SWEEP_SEGMENTS(const list<segment>& L1, 
  343.                     const list<segment>& L2, GRAPH<point,int>& SUB)
  344. {
  345.   S_point    p,inter;
  346.   S_segment  seg, l,lsit,lpred,lsucc,lpredpred;
  347.   pq_item  pqit,pxmin;
  348.   seq_item sitmin,sit,sitpred,sitsucc,sitpredpred;
  349.  
  350.  
  351.   int count=1;
  352.  
  353.   //initialization of the X-structure
  354.  
  355.   segment s;
  356.  
  357.   forall(s,L1) 
  358.    { S_point p = new S_POINT(s.start());
  359.      S_point q = new S_POINT(s.end());
  360.      seg = new S_SEGMENT(p,q,0,count++);
  361.      Xinsert(nil,get_startpoint(seg));
  362.    }
  363.  
  364.   count = -1;
  365.  
  366.   forall(s,L2) 
  367.    { S_point p = new S_POINT(s.start());
  368.      S_point q = new S_POINT(s.end());
  369.      seg = new S_SEGMENT(p,q,1,count--);
  370.      Xinsert(nil,get_startpoint(seg));
  371.    }
  372.  
  373.  
  374.   count = 0;
  375.  
  376.   x_sweep = -MAXINT;
  377.   y_sweep = -MAXINT;
  378.  
  379.  
  380.   while(!X_structure.empty())
  381.   {
  382.     pxmin = X_structure.find_min();
  383.     p = X_structure.inf(pxmin);
  384.  
  385.     sitmin = X_structure.key(pxmin);
  386.  
  387.     Xdelete(pxmin);
  388.  
  389.  
  390.  
  391.     if (sitmin == nil) //left endpoint
  392.     { 
  393.  
  394.       l = get_seg(p); 
  395.  
  396.       x_sweep = get_x(p);
  397.       y_sweep = get_y(p);
  398.  
  399.  
  400.       if (get_x(p) == get_x(get_endpoint(l)))
  401.         handle_vertical_segment(SUB,l);
  402.       else
  403.       {
  404.  
  405. /*
  406.       sit = Y_structure.lookup(l);
  407.       if (sit!=nil)  
  408.            error_handler(1,"plane sweep: sorry, overlapping segments");
  409. */
  410.  
  411.  
  412.       sit = Y_structure.insert(l,nil);
  413.  
  414.       Xinsert(sit,get_endpoint(l));
  415.  
  416.       sitpred = Y_structure.pred(sit);
  417.       sitsucc = Y_structure.succ(sit);
  418.  
  419.       if (sitpred != nil) 
  420.       { if ((pqit = Y_structure.inf(sitpred)) != nil)
  421.           delete Xdelete(pqit);
  422.  
  423.         lpred = Y_structure.key(sitpred);
  424.  
  425.         Y_structure.change_inf(sitpred,nil);
  426.  
  427.         if (intersection(lpred,l,inter))
  428.             Y_structure.change_inf(sitpred,Xinsert(sitpred,inter));
  429.       }
  430.  
  431.  
  432.       if (sitsucc != nil)
  433.       { lsucc = Y_structure.key(sitsucc);
  434.         if (intersection(lsucc,l,inter))
  435.            Y_structure.change_inf(sit,Xinsert(sit,inter));
  436.       }
  437.      } /* else if vertical */
  438.  
  439.     }
  440.     else if (get_kind(p) == Rightend)
  441.          //right endpoint
  442.          { 
  443.            x_sweep = get_x(p);
  444.            y_sweep = get_y(p);
  445.  
  446.            sit = sitmin;
  447.  
  448.            sitpred = Y_structure.pred(sit);
  449.            sitsucc = Y_structure.succ(sit);
  450.  
  451.            S_segment seg = Y_structure.key(sit);
  452.  
  453.            Y_structure.del_item(sit);
  454.  
  455.            delete seg;
  456.  
  457.            if((sitpred != nil)&&(sitsucc != nil))
  458.            {
  459.              lpred = Y_structure.key(sitpred);
  460.              lsucc = Y_structure.key(sitsucc);
  461.              if (intersection(lsucc,lpred,inter))
  462.                 Y_structure.change_inf(sitpred,Xinsert(sitpred,inter));
  463.            }
  464.          }
  465.          else // point of intersection
  466.          { 
  467.            node w = New_Node(SUB,get_x(p),get_y(p));
  468.  
  469.            count++;
  470.  
  471.            /* Let L = list of all lines intersecting in p 
  472.  
  473.               we compute sit     = L.head();
  474.               and        sitpred = L.tail();
  475.  
  476.               by scanning the Y_structure in both directions 
  477.               starting at sitmin;
  478.  
  479.            */
  480.  
  481.            /* search for sitpred upwards from sitmin: */
  482.  
  483.            Y_structure.change_inf(sitmin,nil);
  484.  
  485.            sitpred = Y_structure.succ(sitmin);
  486.  
  487.  
  488.            while ((pqit=Y_structure.inf(sitpred)) != nil)
  489.            { S_point q = X_structure.inf(pqit);
  490.              if (compare(p,q) != 0) break; 
  491.              X_structure.del_item(pqit);
  492.              Y_structure.change_inf(sitpred,nil);
  493.              sitpred = Y_structure.succ(sitpred);
  494.             }
  495.  
  496.  
  497.            /* search for sit downwards from sitmin: */
  498.  
  499.            sit = sitmin;
  500.  
  501.            seq_item sit1;
  502.            
  503.            while ((sit1=Y_structure.pred(sit)) != nil)
  504.            { pqit = Y_structure.inf(sit1);
  505.              if (pqit == nil) break;
  506.              S_point q = X_structure.inf(pqit);
  507.              if (compare(p,q) != 0) break; 
  508.              X_structure.del_item(pqit);
  509.              Y_structure.change_inf(sit1,nil);
  510.              sit = sit1;
  511.             }
  512.  
  513.  
  514.  
  515.            // insert edges to p for all S_segments in sit, ..., sitpred into SUB
  516.            // and set left node to w 
  517.  
  518.            lsit = Y_structure.key(sitpred);
  519.  
  520.            node v = get_left_node(lsit);
  521.            if (v!=nil) New_Edge(SUB,v,w,lsit);
  522.            set_left_node(lsit,w);
  523.  
  524.            for(sit1=sit; sit1!=sitpred; sit1 = Y_structure.succ(sit1))
  525.            { lsit = Y_structure.key(sit1);
  526.  
  527.              v = get_left_node(lsit);
  528.              if (v!=nil) New_Edge(SUB,v,w,lsit);
  529.              set_left_node(lsit,w);
  530.             }
  531.  
  532.            lsit = Y_structure.key(sit);
  533.            lpred=Y_structure.key(sitpred);
  534.            sitpredpred = Y_structure.pred(sit);
  535.            sitsucc=Y_structure.succ(sitpred);
  536.  
  537.  
  538.            if (sitpredpred != nil)
  539.             { 
  540.               lpredpred=Y_structure.key(sitpredpred);
  541.  
  542.               if ((pqit = Y_structure.inf(sitpredpred)) != nil)
  543.                 delete Xdelete(pqit);
  544.  
  545.               Y_structure.change_inf(sitpredpred,nil);
  546.  
  547.  
  548.               if (intersection(lpred,lpredpred,inter))
  549.                 Y_structure.change_inf(sitpredpred,
  550.                                        Xinsert(sitpredpred,inter));
  551.              }
  552.  
  553.  
  554.            if (sitsucc != nil)
  555.             {
  556.               lsucc=Y_structure.key(sitsucc);
  557.  
  558.               if ((pqit = Y_structure.inf(sitpred)) != nil)
  559.                 delete Xdelete(pqit);
  560.                  
  561.               Y_structure.change_inf(sitpred,nil);
  562.  
  563.               if (intersection(lsucc,lsit,inter))
  564.                   Y_structure.change_inf(sit,Xinsert(sit,inter));
  565.              }
  566.  
  567.  
  568. // reverse the subsequence sit, ... ,sitpred  in the Y_structure
  569.  
  570.            x_sweep = get_x(p);
  571.            y_sweep = get_y(p);
  572.  
  573.            Y_structure.reverse_items(sit,sitpred);
  574.  
  575.           delete p;
  576.  
  577.          } // intersection
  578.  
  579.   }
  580.  
  581.   X_structure.clear();
  582.  
  583. }
  584.